#!/usr/bin/ruby

############################################################
#        MFint.rb                                                                              
#        description;                                                                          
#            provide interface for MFd.rb                                                      
#        version           1.5                                     
#        last modified     06/23/06                                                            
#				 revised for ipv6	 12/17/2010
#       added custom option to interface config, relies on int.stop/int.start inside your interface layout
#       added /jail/acl/opts/zone.order capabilities, zones listed there will be processed first in order
#           remaining zones will be processed in directory sort order
############################################################

INT_VERSION=1.5
def int_ver
   return "\tINTERFACE library version: #{INT_VERSION}\n"
end

def activate_int(int,ip,netmask,count,mac)
    retary=Array.new
		if ipv4(ip)	
			if $ipv4int
		  	if count == 0
  	     	if ip.index(/TRAN/i)
    	       if !system("#{$ifconfig} #{int} 0.0.0.0 up")
      	         retary << "\tFAILED: adding TRANSPARENT interface #{int}\n"
      		    end
	      	 elsif !system("#{$ifconfig} #{int} #{ip} netmask #{netmask} broadcast #{find_broadcast(ip,netmask)} #{mac}")
  	         retary << "\tFAILED: ifconfig #{int} #{ip} netmask #{netmask}  broadcast #{find_broadcast(ip,netmask)} #{mac}\n"
    		   end       
	    	else
        	if !system("#{$ifconfig} #{int}:#{count} #{ip} netmask #{netmask} broadcast #{find_broadcast(ip,netmask)} #{mac}")
          	  retary << "\tFAILED: ifconfig #{int}:#{count} #{ip} netmask #{netmask}  broadcast #{find_broadcast(ip,netmask)} #{mac}\n"
	        end
  	  	end
			end #check if we are doing ipv4
		else
			#we got an ipv6 address
			print "We got IPv6 to add: #{ip} #{netmask} dev #{int}\n"
			if !system("#{$ip} -6 addr add #{ip}/#{netmask} dev #{int}")
				retary << "\tFAILED: {$ip} addr add #{ip}/#{netmask} dev #{int} for IPv6\n"
				end
			if !system("#{$ifconfig} #{int} up")
				retary << "\tFAILED: ifconfig bringing #{int} up\n"
				end
		end

    return retary.to_s
end

def make_vlan(master,interface,count)
    retary=Array.new
        if !system("#{$vconfig} set_name_type VLAN_PLUS_VID_NO_PAD")
            retary << "\tFAILED: setting VLAN name_type\n"
        end
        vid=interface.gsub(/[^0-9]/,"")
		print "#{$vconfig} add #{master} #{vid}\n"
        if !system("#{$vconfig} add #{master} #{vid}")
            retary << "\tFAILED: #{$vconfig} add #{master} #{vid}\n"
        end
    return retary.to_s
end

def activate_vlan(dat,count)
    retary=Array.new
    if count == 0
        # do vlan creation stuff
        retary << make_vlan(dat[1],dat[2],count)
        # now activate as standard interface
        retary << activate_int("#{dat[2]}",dat[3],dat[4],count,dat[5])
    else
        # already activated vlan, just create interface
        retary << activate_int(dat[2],dat[3],dat[4],count,dat[5])
    end
    return retary.to_s
end

def drop_int(int)
    retary=Array.new
    if !test(?r, "#{int}/int")
        return "Interface description for zone #{int} not found\n"
    end
    interface=MFreadlines("#{int}/int").shift
    type=MFreadlines("#{int}/type").shift
    if type && type.downcase.include?("vlan")
        if !system("#{$vconfig} rem #{interface}")
            return "\tFAILED: removing vlan interface #{interface}\n"
        end
        return
    end
    if type && type.downcase.include?("custom")
        if !test(?x, "#{int}/int.stop")
       		return "Interface #{int} is set to custom, but there is no int.stop script"
        end
       	retary <<  `/bin/bash #{int}/int.stop`
		return retary
    end
    if ($VERBOSE)
        retary << "ifconfig #{interface} down\n"
    end
    my_list=open("|#{$ifconfig}")
    my_list.each {|down_line|
        next if !down_line.include?(interface)
        tmp=down_line.split(" ")
        down_me=tmp[0]
        if  !system("ifconfig #{down_me} down")
            retary << "\tFAILED: ifconfig #{interface} down\n"
        end
        if  !system("#{$ip} addr flush dev  #{down_me} ")
            retary << "\tFAILED: #{$ip} addr flush dev  #{down_me} \n"
        end
    }
    return retary.to_s
end

def get_interface_specs(int)
    retary=Array.new
    if !test(?r, "#{int}/int") || !test(?r,"#{int}/ip") || !test(?r, "#{int}/netmask")
        return nil
    end
    interface=MFreadlines("#{int}/int").shift
    ip=MFreadlines("#{int}/ip")
    netmask=MFreadlines("#{int}/netmask")
    if test(?r,"#{int}/type")
        itype=MFreadlines("#{int}/type").shift
    else
        itype="physical"
    end
    if test(?r,"#{int}/master")
        master=MFreadlines("#{int}/master").shift
    else
        master=interface
    end
    maddr=MFreadlines("#{int}/MAC")
    mac=nil
    if maddr && maddr[0]
        mac="hw ether #{maddr[0]}"
    end
    count=0
    if netmask[0]
        defnetmask=netmask[0].chomp
    else
        defnetmask="255.255.255.255"
    end
    ip.each {|i|
        if !netmask[count]
            nm=defnetmask
        else
            nm=netmask[count].chomp
        end
        retary << "#{itype}|#{master}|#{interface}|#{i}|#{nm}|#{mac}\n"
        count +=1
    }
    return retary
        
end

def int_start(tzone="all")
	retary=Array.new
	ordered_zones=Array.new
	if tzone == "all"
		if test(?r,"/jail/acl/opts/zone.order")
			ordered_zones=MFreadlines("/jail/acl/opts/zone.order")
			end
		dir=Dir.new("/jail/acl/zones/")
		dir.each {|zname|
			next if ordered_zones.include?(zname)
			ordered_zones << zname
			}
		ordered_zones.each {|zone|
			next if zone.include?("\.")
			next if ! test(?r, "/jail/acl/zones/#{zone}/interface")
			if active?("/jail/acl/zones/#{zone}")
				retary << "\tActivating interface for zone #{zone}\n"
				type=MFreadlines("/jail/acl/zones/#{zone}/interface/type").shift
				if type && type.downcase.include?("custom")
					if !test(?x, "/jail/acl/zones/#{zone}/interface/int.start")
						return "Interface #{zone} is set to custom, but there is no int.start script"
					end
					retary << `/bin/bash /jail/acl/zones/#{zone}/interface/int.start`
					# Need to activate custom int ip
					intconfigip(zone)
					#End activate custom int ip
				else
					interfaces=get_interface_specs("/jail/acl/zones/#{zone}/interface")
					if !interfaces
						retary << "\t\tInvalid interface confiuration... skipping\n"
					end
					count = 0
					interfaces.each {|line|
						dat=line.split("|")
						if dat[0].downcase.include?("vlan")
							retary << activate_vlan(dat,count)
						else
							retary << activate_int(dat[2],dat[3],dat[4],count,dat[5])
						end
						count +=1
					}		
				end

			else
				retary << "\tZONE #{zone} is deactivated by config.. skipping\n"
			end
		}
# now do the arp
retary << arp_start
    else
    if active?("/jail/acl/zones/#{tzone}")
                retary << "\tActivating interface for zone #{tzone} \n"
		type=MFreadlines("/jail/acl/zones/#{tzone}/interface/type").shift
    		if type && type.downcase.include?("custom")
	        	if !test(?x, "/jail/acl/zones/#{tzone}/interface/int.start")
        	        	return "Interface #{tzone} is set to custom, but there is no int.start script"
        		end
			retary << `/bin/bash /jail/acl/zones/#{tzone}/interface/int.start`
			intconfigip(tzone)
		else
			#interfaces=get_interface_specs("/jail/acl/zones/#{tzone}/interface")
			#               	if !interfaces
			#                   		retary << "\t\tInvalid interface confiuration... skipping\n"
			#               	end
			#               	count = 0
			#               	interfaces.each {|line|
			#                   		dat=line.split("|")
			#                   		if dat[0].downcase.include?("vlan")
			#                       		retary << activate_vlan(dat,count)
			#                   		else
			#                    	 		retary << activate_int(dat[2],dat[3],dat[4],count,dat[5])
			#                   		end
			#                   	count +=1
			#       		}
			intconfigip(tzone)
		end
            else
                retary << "\tZONE #{tzone} is deactivated by config.. skipping\n"
            end   
    end
    return(retary.to_s)
end

def intconfigip(zone)
	retary=Array.new
	#Put the right ip on the interface
	interfaces=get_interface_specs("/jail/acl/zones/#{zone}/interface")
	if !interfaces
		retary << "\t\tInvalid interface confiuration... skipping\n"
	end
	count = 0
	interfaces.each {|line|
		dat=line.split("|")
		if dat[0].downcase.include?("vlan")
			retary << activate_vlan(dat,count)
		else
			retary << activate_int(dat[2],dat[3],dat[4],count,dat[5])
		end
		count +=1
	}		
	return(retary.to_s)
end


def int_stop(tzone="all")
    retary=Array.new
    ordered_zones=Array.new
        if tzone == "all"
            if test(?r,"/jail/acl/opts/zone.order")
                ordered_zones=MFreadlines("/jail/acl/opts/zone.order")
            end
        dir=Dir.new("/jail/acl/zones/")
        dir.each {|zname|
            next if ordered_zones.include?(zname)
            ordered_zones << zname
        }
        ordered_zones.each {|zone|
            next if zone.include?("\.")
            next if ! test(?r, "/jail/acl/zones/#{zone}/interface")
            retary << "\tDeactivating interface for zone #{zone}\n"
            retary << drop_int("/jail/acl/zones/#{zone}/interface")
            }
        # now drop the arp
        retary << arp_stop
    else
        retary << "\tDeactivating interface for zone #{tzone}\n"
        retary << drop_int("/jail/acl/zones/#{tzone}/interface")
    end
    return(retary.to_s)
end

def vlans_stop()
    retary=Array.new
    dir=Dir.new("/jail/acl/zones/")
        dir.each {|zone|
        next if zone.include?("\.")
        next if ! test(?r, "/jail/acl/zones/#{zone}/interface")
        next if ! test(?r, "/jail/acl/zones/#{zone}/interface/type")    
        ztype=MFreadlines("/jail/acl/zones/#{zone}/interface/type").shift
        next if ! ztype.downcase == "vlan"
        retary << "\tDeactivating interface for zone #{zone}\n"
        retary << drop_int("/jail/acl/zones/#{zone}/interface")
        }
    retary << arp_stop
    return(retary.to_s)
end

def vlans_start()
    retary=Array.new
    dir=Dir.new("/jail/acl/zones/")
    dir.each {|zone|
    next if zone.include?("\.")
    next if ! test(?r, "/jail/acl/zones/#{zone}/interface")
    next if ! test(?r, "/jail/acl/zones/#{zone}/interface/type")    
    ztype=MFreadlines("/jail/acl/zones/#{zone}/interface/type").shift
    next if ! ztype.downcase == "vlan"
    if active?("/jail/acl/zones/#{zone}")
        retary << "\tActivating interface for zone #{zone}\n"
        interfaces=get_interface_specs("/jail/acl/zones/#{zone}/interface")
        if !interfaces
            retary << "\t\tInvalid interface confiuration... skipping\n"
        end
        count = 0
        interfaces.each {|line|
            dat=line.split("|")
            if dat[0].downcase.include?("vlan")
                retary << activate_vlan(dat,count)
            else
                retary << activate_int(dat[2],dat[3],dat[4],count,dat[5])
            end
            count +=1
            }
    else
        retary << "\tZONE #{zone} is deactivated by config.. skipping\n"
    end
    }
# now do the arp
retary << arp_start
return retary.to_s
end


def int_restart(zone)
    retary=Array.new
    retary << int_stop(zone)
    retary << int_start(zone)
    return (retary.to_s)
end

def vlans_restart()
    retary=Array.new
    retary << vlans_stop()
    retary << vlans_start()
    return retary.to_s
end
